﻿using System.Collections.Generic;
using Microsoft.Xna.Framework;

namespace Engine.Oct
{
    public class OctNode
    {
        public OctNode(OctNode parent,BoundingBox boundingBox )
        {
            Parent = parent;
            BoundingBox = boundingBox;
        }  
        #region Properties

        public OctNode Parent { get; private set; }        
        public IOctObject[] Objects { get; private set; }
        public BoundingBox BoundingBox { get; private set; }
        public OctNode[] Childs { get; private set; }

        #endregion

        #region Public Methods

        public void BuildNode(IOctObject[] objects)
        {
            Objects = objects;
            BoundingBox[] childBoundingBoxes = GetEightChildBoundingBoxes();
            List<IOctObject>[] childNodesObjects = GetChildNodesObjects(childBoundingBoxes);
            BuildChilds(childBoundingBoxes, childNodesObjects);
        }

        #endregion

        #region Private Methods

        private List<IOctObject>[] GetChildNodesObjects(BoundingBox[] childBoundingBoxes)
        {
            List<IOctObject>[] childNodesObjects = new List<IOctObject>[8];
            for (int i = 0; i < childNodesObjects.Length; i++)
                childNodesObjects[i] = new List<IOctObject>();

            foreach (IOctObject octObject in Objects)
            {
                for (int j = 0; j < childBoundingBoxes.Length; j++)
                {
                    if (octObject.Intersects(childBoundingBoxes[j]))
                    {
                        childNodesObjects[j].Add(octObject);
                    }
                }
            }
            return childNodesObjects;
        }
        private void BuildChilds(BoundingBox[] childBoundingBoxes, List<IOctObject>[] childNodesObjects)
        {
            Childs = new OctNode[8];

            for (int i = 0; i < childBoundingBoxes.Length; i++)
            {
                if (childNodesObjects[i].Count != 0 && childNodesObjects[i].Count < Objects.Length)
                {
                    OctNode newNode = new OctNode(this, childBoundingBoxes[i]);
                    newNode.BuildNode(childNodesObjects[i].ToArray());
                    Childs[i] = newNode;
                    continue;
                }
            }
        }
        private BoundingBox[]GetEightChildBoundingBoxes()
        {
            Vector3 min = BoundingBox.Min;
            Vector3 max = BoundingBox.Max;
            Vector3 half = (BoundingBox.Max - BoundingBox.Min) / 2;

            Vector3 halfx = Vector3.UnitX * half;
            Vector3 halfy = Vector3.UnitY * half;
            Vector3 halfz = Vector3.UnitZ * half;

            BoundingBox box1 = new BoundingBox(min, min + half);
            BoundingBox box2 = new BoundingBox(min + halfx, max - half + halfx);
            BoundingBox box3 = new BoundingBox(min + halfz, min + half + halfz);
            BoundingBox box4 = new BoundingBox(min + halfx + halfz, max - halfy);
            BoundingBox box5 = new BoundingBox(min + halfy, max - halfx - halfz);
            BoundingBox box6 = new BoundingBox(min + halfy + halfx, max - halfz);
            BoundingBox box7 = new BoundingBox(min + halfy + halfz, max - halfx);
            BoundingBox box8 = new BoundingBox(min + half, max);

            return new[] { box1, box2, box3, box4, box5, box6, box7, box8 };
        }

        #endregion
    }
}
